package srdb.migration.dbhandler.mysql;

import java.io.InputStream;
import java.io.PipedOutputStream;
import java.sql.SQLException;
import java.sql.Timestamp;

import srdb.migration.MigrationToolkit;
import srdb.migration.Utility;
import srdb.migration.common.IMTKConnection;
import srdb.migration.common.MTKConstants;
import srdb.migration.common.MTKData;
import srdb.migration.schema.metadata.Column;
import srdb.migration.schema.metadata.LargeBufferInputStream;
import srdb.migration.schema.metadata.Table;

public class Data extends MTKData {
	private IMTKConnection conn = null;
	private MTKConstants.DATABASE_TYPE sourceDBType;

	public Data(IMTKConnection conn, int cpBatchSize,
			MTKConstants.DATABASE_TYPE sourceDBType) {
		this.conn = conn;
		this.dbConn = conn.getConnection();
		if (cpBatchSize != 0) {
			MaxBufferSize = 1048576 * cpBatchSize;
		}
		this.sourceDBType = sourceDBType;
	}

	public void setTableData(String tableName, InputStream pis,
			char copyDelimiter) throws Exception {
		throw new Exception("This class doesn't support set method.");
	}

	public LargeBufferInputStream getTableData(
			MTKConstants.DATABASE_TYPE sourceDBType,
			MTKConstants.DATABASE_TYPE targetDBType, Table table,
			char copyDelimeter, boolean escapeTabDelimiter) throws Exception {
		LargeBufferInputStream pis = new LargeBufferInputStream(MaxBufferSize);
		PipedOutputStream pos = new PipedOutputStream();
		String newLineSequence = "\\\\n";
		String carriageReturnSequence = "\\\\r";
		String columnTabDelimiter = "\\\\t";
		pis.connect(pos);
		try {
			if (!this.hasMoreData) {
				if (this.lastTable.compareToIgnoreCase(table.getFullName()) != 0) {
					if (MigrationToolkit.fetchSize == 1) {
						this.stmt = this.dbConn.createStatement(1003, 1007);

						this.stmt.setFetchSize(-2147483648);
					} else {
						this.stmt = this.dbConn.createStatement();

						if (MigrationToolkit.fetchSize > 0) {
							this.stmt.setFetchSize(MigrationToolkit.fetchSize);
						}
					}

					this.rs = this.stmt.executeQuery(table
							.getSelectSQL(sourceDBType));
					this.lastTable = table.getFullName();
				} else {
					return null;
				}
			}

			while (this.rs.next()) {

				for (int i = 0; i < table.getColumns().size(); i++) {
					String lastField = null;
					boolean largeObjFlag = false;
					label980: if ((this.rs.wasNull()) || (largeObjFlag)) {
						pos.write(new String("\\N").getBytes());
					} else {
						pos.write(lastField.getBytes());
					}
					switch (Column.DataType.values()[table.getColumns().get(i)
							.getDataType().ordinal()]) {

					case INTEGER:
						if (this.rs.getObject(i + 1) == null)
							break;
						lastField = String.valueOf(this.rs.getInt(i + 1));
						break;
					// case VARCHAR:
					// case NVARCHAR:
					// case TEXT:
					// case 5:
					case TEXT:
						lastField = this.rs.getString(i + 1);

						if (lastField == null)
							break;
						lastField = lastField.replaceAll("\n", newLineSequence);
						lastField = lastField.replaceAll("\r",
								carriageReturnSequence);
						if ((escapeTabDelimiter) && (copyDelimeter == '\t')) {
							lastField = lastField.replaceAll("\t",
									columnTabDelimiter);
						}

						if (!lastField.endsWith("\\"))
							break;
						lastField = lastField.concat("\\");
						break;
					case FLOAT:
						if (this.rs.getObject(i + 1) == null)
							break;
						lastField = new Double(this.rs.getDouble(i + 1))
								.toString();
						break;
					// case 8:
					// case 9:

					case NUMERIC:
						Column column = table.getColumns().get(i);
						if (this.rs.getObject(i + 1) == null)
							break;
						if (column.isReal()) {
							lastField = new Float(this.rs.getFloat(i + 1))
									.toString();
							break;
						}
						if (column.isDouble()) {
							lastField = new Double(this.rs.getDouble(i + 1))
									.toString();
							break;
						}
						lastField = this.rs.getBigDecimal(i + 1).toString();
						break;
					case TIME:
						if (this.rs.getTime(i + 1) == null)
							break;
						lastField = this.rs.getTime(i + 1).toString();
						break;
					case DATE:
						if (sourceDBType != MTKConstants.DATABASE_TYPE.SQLSERVER)
							break;
						if (this.rs.getDate(i + 1) == null)
							break;
						lastField = this.rs.getDate(i + 1).toString();
						break;
					case TIMESTAMP:
						try {
							if (this.rs.getTimestamp(i + 1) != null) {
								lastField = this.rs.getTimestamp(i + 1)
										.toString();
							}
						} catch (Exception exp) {
							if (((exp instanceof SQLException))
									&& (((SQLException) exp).getSQLState()
											.equalsIgnoreCase("S1009")))
								try {
									if (exp.getMessage().contains(
											"0000-00-00 00:00:00"))
										lastField = "0000-00-00 00:00:00";
									else {
										lastField = "0000-00-00";
									}

									lastField = Utility
											.formatMySQLZeroDateTimeToPG(lastField);
								} catch (Exception e) {
								}
							else
								lastField = new Timestamp(
										Long.parseLong(this.rs.getString(i + 1)))
										.toString();

						}

					case BINARY_FLOAT:
						largeObjFlag = true;
						break;
					case BYTEA:
						if (this.rs.getString(i + 1) == null)
							break;
						lastField = this.rs.getString(i + 1);
						break;

					default:
						if (this.rs.getMetaData().getColumnTypeName(i + 1)
								.equalsIgnoreCase("CHAR")) {
							lastField = this.rs.getString(i + 1);
						} else {
							if ((this.rs.getMetaData().getColumnTypeName(i + 1)
									.equalsIgnoreCase("CLOB"))
									|| (this.rs.getMetaData()
											.getColumnTypeName(i + 1)
											.equalsIgnoreCase("NCLOB"))) {
								throw new Exception(
										"This Table Contains CLOB data, Marked for Bulk Insert Loading");
							}
							throw new Exception(this.rs.getMetaData()
									.getColumnTypeName(i + 1)
									+ " is Not Supported by COPY");
						}

						if (i < table.getColumns().size() - 1)
							pos.write(copyDelimeter);
					}

					pos.write(10);

					pis.addRowNum();

					if (MaxBufferSize - pis.getLength() < table.getMaxRowSize()) {
						pos.flush();
						pos.close();
						this.hasMoreData = true;
						return pis;
					}
				}
			}

			this.rs.close();
			this.stmt.close();
			this.hasMoreData = false;
			pos.flush();
			pos.close();
		} catch (Exception ex) {
			throw ex;
		}

		return pis;
	}

	public int setTableDataViaDBLinkOra(String tableName, String targetSchema,
			String targetTable, boolean truncate) throws SQLException {
		throw new UnsupportedOperationException("Not supported yet.");
	}
}

/*

 */